package visitor;

import java.util.Vector;

import symboltable.Class;
import symboltable.Method;


import syntaxtree.ClassDecl;

import symboltable.Symbol;
import symboltable.SymbolTable;

import syntaxtree.And;
import syntaxtree.ArrayAssign;
import syntaxtree.ArrayLength;
import syntaxtree.ArrayLookup;
import syntaxtree.Assign;
import syntaxtree.Block;
import syntaxtree.BooleanType;
import syntaxtree.Call;
import syntaxtree.ClassDeclExtends;
import syntaxtree.ClassDeclSimple;
import syntaxtree.False;
import syntaxtree.Formal;
import syntaxtree.Identifier;
import syntaxtree.IdentifierExp;
import syntaxtree.IdentifierType;
import syntaxtree.If;
import syntaxtree.IntArrayType;
import syntaxtree.StringArrayType;
import syntaxtree.IntegerLiteral;
import syntaxtree.IntegerType;
import syntaxtree.LessThan;
import syntaxtree.MainClass;
import syntaxtree.MethodDecl;
import syntaxtree.Minus;
import syntaxtree.NewArray;
import syntaxtree.NewObject;
import syntaxtree.Not;
import syntaxtree.Plus;
import syntaxtree.Print;
import syntaxtree.Program;
import syntaxtree.This;
import syntaxtree.Times;
import syntaxtree.True;
import syntaxtree.VarDecl;
import syntaxtree.VoidType;
import syntaxtree.While;

public class SymbolTableVisitor implements Visitor {

	private SymbolTable symbol_table;
	
	public SymbolTable build_table(Program prog)
	{
		symbol_table = new SymbolTable();
		visit(prog);
		return symbol_table;
	}
	
	@Override
	public void visit(Program prog) {
		// TODO Auto-generated method stub
		// Runs the symbol table visitor on the main class
		prog.m.accept(this);
		// and on all other class declarations
		for(int i = 0; i < prog.cl.size(); i++){
			prog.cl.elementAt(i).accept(this);
		}
	}

	@Override
	public void visit(MainClass n) {
		symbol_table.add_class(Symbol.symbol(n.i1.s), null);
		symbol_table.begin_class_scope(Symbol.symbol(n.i1.s));
		Vector<Formal> main_args = new Vector<Formal>();
		main_args.add(new Formal(new StringArrayType(), n.i2));
		symbol_table.add_method(new VoidType(), Symbol.symbol("main"), main_args);
		// TODO: need to begin and end method scope?
		symbol_table.end_class_scope();
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(ClassDeclSimple n) {
		// If we are able to add that class
		if ( symbol_table.add_class(Symbol.symbol(n.i.s), null) != null ) {
			symbol_table.begin_class_scope(Symbol.symbol(n.i.s));
			for ( int i = 0; i < n.vl.size(); i++ ) {
				n.vl.elementAt(i).accept(this); 
			}
			for ( int i = 0; i < n.ml.size(); i++ ) {
				n.ml.elementAt(i).accept(this);
			}
			symbol_table.end_class_scope();
		}
	}

	@Override
	public void visit(ClassDeclExtends n) {
		// If we are able to add that class
		if ( symbol_table.add_class(Symbol.symbol(n.i.s), Symbol.symbol(n.j.s)) != null ) {
			symbol_table.begin_class_scope(Symbol.symbol(n.i.s), Symbol.symbol(n.j.s));
			for ( int i = 0; i < n.vl.size(); i++ ) {
				n.vl.elementAt(i).accept(this); 
			}
			for ( int i = 0; i < n.ml.size(); i++ ) {
				n.ml.elementAt(i).accept(this);
			}
			symbol_table.end_class_scope();
		}
	}

	@Override
	public void visit(VarDecl n) {
		symbol_table.add_variable(Symbol.symbol(n.i.s), n.t);
	}

	@Override
	public void visit(MethodDecl n) {
		Vector<Formal> pars = new Vector<Formal>();
		for (int i = 0; i < n.fl.size(); i++) {
			pars.add(n.fl.elementAt(i));
		}
		if ( symbol_table.add_method(n.t, Symbol.symbol(n.i.s), pars) != null ) {
			symbol_table.begin_method_scope(n.t, Symbol.symbol(n.i.s), pars);
			for(int i = 0; i < n.fl.size(); i++) {
				n.fl.elementAt(i).accept(this);
			}
			for(int i = 0; i < n.vl.size(); i++) {
				n.vl.elementAt(i).accept(this);
			}
			symbol_table.end_method_scope();
		}
	}

	@Override
	public void visit(Formal n) {
		symbol_table.add_variable(Symbol.symbol(n.i.s), n.t);
	}

	@Override
	public void visit(IntArrayType n) {
		// TODO Auto-generated method stub

	}
	
	@Override
	public void visit(StringArrayType n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(BooleanType n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(IntegerType n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(IdentifierType n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Block n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(If n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(While n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Print n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Assign n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(ArrayAssign n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(And n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(LessThan n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Plus n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Minus n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Times n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(ArrayLookup n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(ArrayLength n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Call n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(IntegerLiteral n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(True n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(False n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(IdentifierExp n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(This n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(NewArray n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(NewObject n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Not n) {
		// TODO Auto-generated method stub

	}

	@Override
	public void visit(Identifier n) {
		// TODO Auto-generated method stub

	}
	
    // VoidType i;
    public void visit(VoidType n) {
    }

}
